home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / objcissu.lha / multiple-inheritance < prev    next >
Internet Message Format  |  1993-02-07  |  11KB

  1. Date: Thu, 28 Jan 93 20:13:49 -0600
  2. From: Paul Burchard <burchard@localhost.gw.umn.edu>
  3. To: liberte@cs.uiuc.edu
  4. Subject: How to do better than Multiple Inheritance
  5. Cc: gnu-objc-ibex@prep.ai.mit.edu, gnu-objc@prep.ai.mit.edu
  6. Reply-To: burchard@geom.umn.edu
  7.  
  8. [Since this is an important issue I am forwarding this to a couple of
  9. the GNU mailing lists...]
  10.  
  11. Dan LaLiberte <liberte@cs.uiuc.edu> writes:
  12. > What do you think about the possibility of adding
  13. > multiple inheritance to GNU Objective-C?
  14.  
  15. I understand this temptation, arising from the deficiencies of
  16. delegation, but I don't think MI is the answer you're looking for.  MI
  17. is actually a fairly crude tool for inheriting different pieces of
  18. implementation from different classes:
  19.  
  20. (1) MI can't handle the situation where several instances want to
  21. share a "parent" object to which substantial implementation should be
  22. delegated.
  23.  
  24. For example, if you have a document object supports multiple "views"
  25. of itself, you may want each document-view to respond to most of the
  26. messages that the document object itself would respond to.  MI doesn't
  27. address this because it assumes that the "parent" must always be
  28. imbedded in the "child".
  29.  
  30. (2) In cases of conflicting inheritance, you lose all but the coarsest
  31. control over what comes from where.  While fully explicit inheritance
  32. rules can sometimes help, there will still be plenty of situations
  33. where you'll get boxed in by MI.
  34.  
  35. For example, in an intertwined MI hierarchy of Controls and Cells,
  36. GlorpButton might want to inherit from Button and GlorpCell.  Let's
  37. suppose that GlorpCell acts much like ButtonCell, but is implemented
  38. completely differently.  Now MI is hosed!  Button would already have
  39. multi-inherited most Cell methods from ButtonCell.  Thus, even if MI
  40. allowed us to choose a "preferred" parent class, it would provide no
  41. way for GlorpButton to inherit just Cell functionality from GlorpCell.
  42. We're back to explicit delegation.
  43.  
  44. (3) One of Obj-C's hallmarks is that each of its small number of
  45. features is very poweful and flexible for the amount of complexity it
  46. adds to the language.  For example, Protocols are a great addition
  47. because, despite their utter simplicity, they directly support the
  48. correct basis for typing in OOP---functionality, rather than
  49. implementation.  MI, by contrast, is only a partial solution to the
  50. problem it tries to address---reuse of implementation.
  51.  
  52.  
  53. I'd really like to see a good solution to the implementation re-use
  54. problem.  Explicit delegation is flexible enough, but as you know
  55. suffers from several problems:
  56.  
  57. * It generates lots of boilerplate which becomes a maintenance
  58. headache (when you're overriding to inherit from the "other
  59. parent")...or maybe a C preprocessor headache.
  60.  
  61. * It's up to twice as slow as ordinary messaging due to the extra
  62. message call overhead.  Penalties go even higher if you try to make
  63. things more compact by using general runtime delegation mechanisms
  64. like forward::.
  65.  
  66.  
  67. Here's one possible solution (sadly, not compatible with the current
  68. GNU Obj-C run-time).  It provides a concise, but flexible @super
  69. notation to support inheritance of implementation from different parts
  70. of the class hierarchy.  It is transparent to implementation code,
  71. affecting only interface declarations.  In particular, overriding and
  72. modification of inherited implementations looks just like it always
  73. did.
  74.  
  75. The idea is that we can designate Protocols for which the meaning of
  76. "super" in overridden methods---and the meaning of "self" in
  77. non-overridden methods---is modified.  For example, here is how I
  78. imagine the GlorpButton example above being implemented:
  79.  
  80.     @interface GlorpButton : Button
  81.     {
  82.         // Inherit <Cells> methods from GlorpCell class.
  83.         // Make inherited implementations act on state in "cell".       
  84.  
  85.         @super<Cells> GlorpCell *cell;
  86.         ...
  87.     }
  88.     ...
  89.     @end
  90.  
  91. Normally "super" invokes a fixed implementation of the method on a
  92. parent object which lives parasitically inside the child.  But by
  93. designating an associated object to be "@super" for some protocol, an
  94. appropriate fixed implementation can be invoked on a different,
  95. external "parent" object (the designated instance var) instead.
  96.  
  97. In the same way, if a method in the protocol was not overridden, it
  98. would be dispatched by default to the object designated as @super for
  99. that protocol, using the same implementation that would be obtained if
  100. "self" were equal to that associated object.
  101.  
  102. So the intended effect of the above example is that:
  103.  
  104. * All <Cells> methods sent to a GlorpButton would, by default, really
  105. be sent the GlorpButton's "cell" instance variable.  Just as with
  106. ordinary dispatch, the implementation would be chosen at run-time,
  107. depending on the actual sublclass of GlorpCell occupied by "cell".
  108.  
  109. * If GlorpButton overrode a <Cells> method, then any message to
  110. "super" within such an implementation would invoke GlorpCell's
  111. implementation of that message on "cell" (indepedent of the real class
  112. of "cell").  For example:
  113.  
  114.     @implementation GlorpButton
  115.     
  116.     - (int)intValue
  117.     {
  118.         // Compute value using the *inherited* intValue.
  119.         // (This comes from "cell", considered as a GlorpCell.)
  120.        
  121.         return ([super intValue] + 1);
  122.     }
  123.     ...
  124.     @end
  125.  
  126. (To get the intValue of cell according to its runtime class, [cell
  127. intValue] would work as always.)
  128.  
  129. Based on the above example we see that it would have to be permissible
  130. to make stricter redeclarations of existing instance variables, at
  131. least for the purpose of @super designation.  This shouldn't be a big
  132. problem because it doesn't require any retroactive changes to
  133. previously compiled code in superclasses.  Also, note that any @super
  134. variables would have to be statically typed, since the purpose is to
  135. inherit implementation from somewhere.
  136.  
  137. This proposal is not (portably) compatible with the current GNU
  138. Objective-C run-time because the "self" argument to method
  139. implementation calls is hard-compiled in.  If the current message-call
  140. conventions are kept, it also seems that any implementation of @super
  141. would have to be equivalent to explicit delegation or forwarding, and
  142. would thereby incur the corresponding penalties in execution time.
  143.  
  144. --------------------------------------------------------------------
  145. Paul Burchard    <burchard@geom.umn.edu>
  146. ``I'm still learning how to count backwards from infinity...''
  147. --------------------------------------------------------------------
  148.  
  149.  
  150.  
  151. From: billb@jupiter.fnbc.com (Bill Burcham)
  152. Date: Fri, 29 Jan 93 09:34:19 -0600
  153. To: gnu-objc@prep.ai.mit.edu
  154. Subject: Re: How to do better than Multiple Inheritance
  155. Cc: burchard@geom.umn.edu
  156.  
  157. Cool ideas!  I like the idea of using protocols for conflict
  158. resolution in MI.  What I don't see is the need for:
  159.  
  160.     @interface GlorpButton : Button
  161.     {
  162.         // Inherit <Cells> methods from GlorpCell class.
  163.         // Make inherited implementations act on state in "cell".      
  164.  
  165.         @super<Cells> GlorpCell *cell;
  166.         ...
  167.     }
  168.     ...
  169.     @end
  170.  
  171. the cell instance variable to be visible to an instance of GlorpButton
  172. (or maybe visible, but the implementer of GlorpCell shouldn't have to
  173. think up a name for that instance).  Also, are you insinuating that I
  174. would have to alloc a GlorpCell myself in - init?  Would the runtime
  175. do it for me?  Let's say that the runtime _will_ alloc objects and
  176. init all @super outlets with instances of the proper class -- then how
  177. is the better than the runtime alloc'ing a single object with the
  178. superset of all the ivars?  In asking that last question I start to
  179. think maybe there _are_ advantages: maybe it would be nice to have an
  180. ivar in GlorpButton with a name the same as one in Button, but with a
  181. different meaning (this would be nice, so I wouldn't have to worry
  182. about ivar name conflicts in my new subclass: GlorpButton).  I can see
  183. arguments for having seperate objects, but I don't see the need for
  184. the cell ivar in the .h file.  Would this do:
  185.  
  186.     @interface GlorpButton : Button, <Cells> GlorpCell
  187.     {
  188.         ...
  189.     }
  190.     ...
  191.     @end
  192.  
  193. You could still have the runtime actually create a GlorpButton(as a
  194. subclass of Button -- just like it works now) and a GlorpCell.  The
  195. GlorpButton would not usually need direct access to the instance of
  196. GlorpCell.  When GlorpButton needs to get at the id of one of these
  197. superclass objects, we could have an Object method to do so perhaps:
  198.     - superclassInstance:(id)aClassObject;
  199.  
  200. So we could write something like:
  201.  
  202.     [self superclassInstance:GlorpCell];
  203.  
  204. Just some random thoughts.  I also am very intrigued with
  205. prototype-instance languages like (I think) GemStone, and Self, where
  206. there is no distinction between Class objects and "instance" objects.
  207. Any object can be used as a prototype for other objects.  Methods and
  208. ivars can be added/removed/changed at runtime, and objects that
  209. inherit those things dynamically get the altered behavior.  I realize
  210. this is beyond the scope of the GNU Objective-C project but it is
  211. really cool to think about anyhow.
  212.  
  213. ---
  214. +--------------------------------+----------------------------------+
  215. |          Bill Burcham          | "Make no small plans; they have  |
  216. | First National Bank of Chicago | no magic to stir men's souls"    |
  217. |    billb@fnbc.com  (NeXTmail)  |      Daniel J. Burnham           |
  218. +--------------------------------+----------------------------------+
  219.  
  220. Date: Fri, 29 Jan 93 12:19:34 -0600
  221. From: Paul Burchard <burchard@localhost.gw.umn.edu>
  222. To: billb@jupiter.fnbc.com (Bill Burcham)
  223. Subject: Re: How to do better than Multiple Inheritance
  224. Cc: gnu-objc@prep.ai.mit.edu
  225. Reply-To: burchard@geom.umn.edu
  226.  
  227. > Cool ideas!  I like the idea of using protocols for conflict
  228. > resolution in MI.  What I don't see is the need for:
  229. > [...]
  230. > the cell instance variable to be visible to an instance of
  231. > GlorpButton
  232.  
  233. Yes, this is the difficult part of how to do notation for this scheme.
  234. Because of the examples I gave, I think it's important to be able to
  235. use instance variables to hold state for implementations culled from
  236. other parts of the hierarchy, rather than always using imbedded parent
  237. objects.
  238.  
  239. The problem is that the appropriate instance variables are often
  240. already inside some other parent object, and therefore syntactically
  241. inaccessible (for good reason, to be sure).  So there needs to be some
  242. notational system which lets the compiler resolve this.
  243.  
  244. > Would this do:
  245. >     @interface GlorpButton : Button, <Cells> GlorpCell
  246. >     {
  247. >         ...
  248. >     }
  249. >     ...
  250. >     @end
  251.  
  252. This could work if the compiler can figure out where to put the state
  253. for <Cells> methods.  If Control had already set its "cell" instance
  254. var to be a parent object for <Cells> methods, for example, then
  255. perhaps that could imply an interpretation of the above.  Unless such
  256. resolution is possible, maybe use of parent vars for MI should not be
  257. allowed?
  258.  
  259. I appreciate your thoughts...
  260.  
  261. --------------------------------------------------------------------
  262. Paul Burchard    <burchard@geom.umn.edu>
  263. ``I'm still learning how to count backwards from infinity...''
  264. --------------------------------------------------------------------
  265.  
  266.